package com.tyros.common.kit.bean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 序列化、反序列化
 *
 * @author zhangshuaiyin
 * @date 2021-06-22 17:05
 */
public class SerializeKit {

    private static final Logger log = LoggerFactory.getLogger(SerializeKit.class);

    /**
     * 序列化对象
     *
     * @param object 对象
     * @return 对象字节数组
     */
    public static byte[] serialize(Object object) {
        byte[] bytes = null;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            // 序列化
            oos.writeObject(object);
            bytes = baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * 反序列化对象
     *
     * @param bytes 对象字节数组
     * @return 对象
     */
    public static Object deserializer(byte[] bytes) {
        Object obj = null;
        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
             ObjectInputStream ois = new ObjectInputStream(bais)) {
            // 反序列化
            obj = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 关闭的数据源或目标。调用 close()方法可释放对象保存的资源（如打开文件）
     * 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流，则调用此方法无效。
     *
     * @param closeable 关闭资源
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                log.info("Unable to close {}", closeable, e);
            }
        }
    }

    /**
     * 列表序列化（用于Redis整存整取）
     *
     * @param value List<T>
     * @return 字节数组
     */
    public static <T> byte[] serialize(List<T> value) {
        if (value == null) {
            throw new NullPointerException("Can't serialize null");
        }
        byte[] rv;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
             ObjectOutputStream os = new ObjectOutputStream(bos)) {
            for (T obj : value) {
                os.writeObject(obj);
            }
            os.writeObject(null);
            os.close();
            bos.close();
            rv = bos.toByteArray();
        } catch (IOException e) {
            throw new IllegalArgumentException("Non-serializable object", e);
        }
        return rv;
    }

    /**
     * 反序列化列表（用于Redis整存整取）
     *
     * @param in List字节数组
     * @return List
     */
    public static <T> List<T> deserializerForList(byte[] in, Class<T> clazz) {
        List<T> list = new ArrayList<T>();
        if (in != null) {
            try (ByteArrayInputStream bis = new ByteArrayInputStream(in);
                 ObjectInputStream is = new ObjectInputStream(bis)) {
                while (true) {
                    T obj = clazz.cast(is.readObject());
                    if (obj == null) {
                        break;
                    } else {
                        list.add(obj);
                    }
                }
            } catch (IOException e) {
                log.warn("Caught IOException decoding %d bytes of data {}", in.length, e);
            } catch (ClassNotFoundException e) {
                log.warn("Caught ClassNotFoundException decoding %d bytes of data {}", in.length, e);
            }
        }
        return list;
    }
}
